package festival.board;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;

import javax.swing.JPanel;
import javax.xml.ws.handler.Handler;

import festival.board.Board.CoordinatePair;

public class BoardView extends JPanel implements ComponentListener, ObservableModel.ModelChangeListener {
    public static int TYPE_RICE         = 0;
    public static int TYPE_VILLAGE      = 1;
    public static int TYPE_IRRIGATION   = 2;
    public static int TYPE_PALACE       = 3;
    public static int TYPE_EMPTY      	= 4;
    
    private Handler mHandler;
    
    
    public static Color[] sTileColors = {
        new Color(0xFF50c248),  //rice
        new Color(0xFF825e45),  //village
        new Color(0xFF156fdf),  //irrigation
        new Color(0xFF983232),  //palace
        new Color(0xFFFFFFFF)   //empty
    };
    
    public static int PLAYER_1 = 1;
    public static int PLAYER_2 = 2;
    public static int PLAYER_3 = 3;
    public static int PLAYER_4 = 4;
    
    public static Color[] sDevColors = {
        Color.ORANGE,
        Color.RED,
        Color.WHITE,
        Color.BLACK
    };
    
    private static Color TRANSPARENT =  new Color(0, 0, 0, 0);
    
    private static final Color sTopographyColor = new Color(255, 255, 255, 60);
    
    private static final int DEFAULT_STROKE = 3;
    private static final int HIGHLIGHT_STROKE = 5;
    
    private int[] mLastOverlayCoordinates = new int[] { 0, 0 };
    private int[] mAnimCoordinates = new int[] { 0, 0 };
    private long mAnimStartTime;
    private long mElapsedAnimTime;
    
    private double mOverlayOffsetX;
    private double mOverlayOffsetY;
    private double mAnimOffsetX;
    private double mAnimOffsetY;
    
    private boolean mDrawingOverlay;
    private Color mOverlayColor;
    private double mAnimTransX;
    private double mAnimTransY;
    private boolean mAnimating;
    
    private Rectangle2D mDrawableRect;
    
    private int mStrokeWidthAdjust = 0;
    
    private int mNumRows;
    private int mNumColumns;
    
    private double mCenterX;
    private double mCenterY;
    private double mMaxHexWidth;
    private double mHexWidth;
    private double mHexHeight;
    private double mHexSide;
    private double mHexRadius;
    private double mDx;
    private double mDy;
    
    private Board mBoard;
    
    private Polygon mBorderShape;
    private Path2D.Double mBorderPath;
    private Path2D.Double mTileHexagon;
    private Path2D.Double mAnimHexagon;
    private Ellipse2D mDeveloperCircle;
    
    private double mViewOffsetX;
    private double mViewOffsetY;
    
    public BoardView(Board board) {
        super();
        mBoard = board;
        
        int minQ = 1000;
        int minR = 1000;
        int maxQ = -1000;
        int maxR = -1000;
        for(int[] coordinates : board.getMapCoordinates()) {
            int q = coordinates[0];
            int r = coordinates[1];
            
            minQ = Math.min(minQ, q);
            maxQ = Math.max(maxQ, q);
            minR = Math.min(minR, r);
            maxR = Math.max(maxR, r);
        }
        
        mNumRows = maxR - minR;
        mNumRows++;
        mNumColumns = maxQ - minQ;
        
        addComponentListener(this);
    }
    
    public void drawCenteredString(Graphics2D g2, String s, int x, int y) {
        // Find the size of string s in the font of the Graphics context "page"
        FontMetrics fm   = g2.getFontMetrics(g2.getFont());
        java.awt.geom.Rectangle2D rect = fm.getStringBounds(s, g2);
        int textHeight = (int)(rect.getHeight());
        int textWidth  = (int)(rect.getWidth());

        // Center text horizontally and vertically within provided rectangular bounds
        int textX = x - (textWidth)/2;
        int textY = y - (textHeight)/2 + fm.getAscent();
        g2.drawString(s, textX, textY);
    }
    
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if(mBorderShape != null) {
            Graphics2D g2 = (Graphics2D) g;
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
            
            // Paint map
            for(int[] coordinates : mBoard.getMapCoordinates()) {
                Tile tile = mBoard.getTile(coordinates);
                g2.setStroke(new BasicStroke(DEFAULT_STROKE + mStrokeWidthAdjust));
                drawHexagonAtPosition(coordinates, sTileColors[tile.getLandType()], Color.BLACK, g2);
                double[] center = getPixelsFromPosition(coordinates);
                g2.setFont(new Font(Font.MONOSPACED, Font.BOLD, (int) (mHexRadius * 0.4)));
//                drawStringCenteredBoth(g2, "" + coordinates[0] + ", " + coordinates[1], (int) center[0], (int) center[1]);
                double[] pixels = getPixelsFromPosition(coordinates);
                g2.setColor(sTopographyColor);
                g2.setFont(new Font(Font.MONOSPACED, Font.BOLD, (int) (mHexRadius * 1.8)));
                drawCenteredString(g2, mBoard.getElevation(coordinates) + "", 
                        (int) pixels[0], (int) pixels[1]);
                
            }
            
            for(int[] dc : mBoard.getDeveloperCoordinates()) {
                int playerId = mBoard.getDeveloperPlayerIndex(dc);
                drawCircleAtPosition(g2, dc, sDevColors[(playerId)], Color.BLACK, mHexRadius / 3);
            }
            
            for(CoordinatePair pc : mBoard.getPalaceCoordinates()) {
                PalaceTile pt = mBoard.getPalace(pc);
                if(pt != null) {
                    drawPalaceAtPosition(g2, pc.coordinates, pt.getPalaceSize());
                }
            }
            
//            g2.setColor(Color.BLACK);
//            g2.draw(mBorderPath);
//            g2.setColor(Color.RED);
//            g2.drawString(mBorderPath.getBounds().width + " " + mBorderPath.getBounds().height, (int) mCenterX, (int) mCenterY);
            
            
            // Paint overlay
            g2.setStroke(new BasicStroke(HIGHLIGHT_STROKE + mStrokeWidthAdjust));
//            Tile overlay = mBoard.getOverlayTile();
//            int[] overlayCoordinates = mBoard.getOverlayCoordinates();
            if(mBoard.hasTileOverlay()) {
                HashMap<CoordinatePair, Tile> tileOverlay = mBoard.getOverlayTiles();
                if(tileOverlay != null && !tileOverlay.isEmpty()) {
                    Color borderColor = mBoard.canPlaceTile() ? Color.GREEN : Color.RED;
                    for (CoordinatePair cp : tileOverlay.keySet()) {
                        drawHexagonAtPosition(cp.coordinates, 
                                sTileColors[tileOverlay.get(cp).getLandType()], borderColor, g2);
                    }
                }
            } else if(mBoard.hasDeveloperOverlay()) {
                Color borderColor = mBoard.canPlaceDeveloper() ? Color.GREEN : Color.RED;
                int[] devOverlayCoordinates = mBoard.getOverlayDeveloperCoords().coordinates;
                int devOverlayId = mBoard.getOverlayDeveloperPlayerIndex();
                
                System.out.println("drawing dev overlay for " + devOverlayId);
                System.out.println("I mean " + (devOverlayId - 1) % 4);
                drawCircleAtPosition(g2, devOverlayCoordinates, sDevColors[(devOverlayId) % 4], borderColor, mHexRadius / 3);
                
//                calcViewOffsets(g2, devOverlayCoordinates);
            }
            
            int[] selectedDevCoords = mBoard.getCurrentlySelectedDeveloperCoordinates();
            if(selectedDevCoords != null) {
                Color borderColor = Color.YELLOW;
                drawCircleAtPosition(g2, selectedDevCoords, TRANSPARENT, borderColor, mHexRadius / 3);
            }
            
            int[] moveDevCoords = mBoard.getDeveloperMovementTarget();
            if(moveDevCoords != null) {
                Color borderColor = mBoard.canMoveDeveloper() ? Color.GREEN : Color.RED;
                int devOverlayId = mBoard.getDeveloperMovementTargetPlayerIndex();
                drawCircleAtPosition(g2, moveDevCoords, sDevColors[(devOverlayId) % 4], borderColor, mHexRadius / 3);
            }
            
            int[] placePalaceCoords = mBoard.getOverlayPalaceTileCoordinates();
            if(placePalaceCoords != null) {
                System.out.println("drawing palace overlay ");
                int palaceSize = mBoard.getOverlayPalaceTileSize();
                drawPalaceAtPosition(g2, placePalaceCoords, palaceSize);
            }
            
			int[] selectedPalaceCoords = mBoard
					.getCurrentlySelectedPalaceCoordinates();
			if (selectedPalaceCoords != null) {
					Color borderColor = Color.YELLOW;
						drawHexagonAtPosition(selectedPalaceCoords,
								TRANSPARENT,
								borderColor, g2);
			}
        }
    }
    
    private void drawPalaceAtPosition(Graphics2D g2, int[] position, int palaceLevel) {
        System.out.println(palaceLevel);
        Color c = Color.WHITE;
        Color bc = Color.BLACK;
        double tRadius = mHexRadius / 4;
        double pRadius = mHexRadius * 0.5;
        double[] center = getPixelsFromPosition(position);
        for(int i = 0; i < palaceLevel; i++) {
            double radians = ((i * (360 / palaceLevel)) + 45) * Math.PI / 180;
            System.out.println(radians);
            double[] pixels = new double[] {
                    center[0] + pRadius * Math.cos(radians),
                    center[1] + pRadius * Math.sin(radians)
            };
            drawTriangleAtPixel(g2, pixels, c, bc, tRadius);
        }
//        switch(palaceLevel) {
//            case 8 :
//                double[] p7 = new double[] {
//                        center[0],
//                        center[1] + tRadius
//                };
//                double[] p8 = new double[] {
//                        center[0],
//                        center[1] - tRadius
//                };
//                drawTriangleAtPixel(g2, p7, c, bc, tRadius);
//                drawTriangleAtPixel(g2, p8, c, bc, tRadius);
//            case 6 :
//                double[] p5 = new double[] {
//                        center[0] + tRadius,
//                        center[1]
//                };
//                double[] p6 = new double[] {
//                        center[0] - tRadius,
//                        center[1]
//                };
//                drawTriangleAtPixel(g2, p5, c, bc, tRadius);
//                drawTriangleAtPixel(g2, p6, c, bc, tRadius);
//            case 4 :
//                double[] p3 = new double[] {
//                        center[0] - tRadius,
//                        center[1] + tRadius
//                };
//                double[] p4 = new double[] {
//                        center[0] + tRadius,
//                        center[1] - tRadius
//                };
//                drawTriangleAtPixel(g2, p3, c, bc, tRadius);
//                drawTriangleAtPixel(g2, p4, c, bc, tRadius);
//            case 2 :
//                System.out.println("palace size 2");
//                double[] p1 = new double[] {
//                        center[0] + tRadius,
//                        center[1] + tRadius
//                };
//                double[] p2 = new double[] {
//                        center[0] - tRadius,
//                        center[1] - tRadius
//                };
//                drawTriangleAtPixel(g2, p1, c, bc, tRadius);
//                drawTriangleAtPixel(g2, p2, c, bc, tRadius);
//                break;
//        }
    }
    
    private void calcViewOffsets(Graphics2D g2, int[] pos) {
        double[] pixels = getPixelsFromPosition(pos);
        mViewOffsetX = pixels[0] - mCenterX;
        mViewOffsetY = pixels[1] - mCenterY;
        
        AffineTransform transformer = new AffineTransform();
        transformer.translate(mViewOffsetX, mViewOffsetY);
//        transformer.scale(2,2);
        g2.setTransform(transformer);
    }
    
    private void drawTriangleAtPixel(Graphics2D g2, double[] pixels, Color color, Color borderColor, double radius) {
        double centerX = pixels[0];
        double centerY = pixels[1];
        
        Path2D.Double triangle = new Path2D.Double();
        for(int q = 0; q < 4; q++) {
            double radians = ((q * 120) + 30) * Math.PI / 180;
            if(q == 0) {
                triangle.moveTo(centerX + radius * Math.cos(radians), centerY + radius * Math.sin(radians));
            } else {
                triangle.lineTo(centerX + radius * Math.cos(radians), centerY + radius * Math.sin(radians));
            }
        }
        
        g2.setStroke(new BasicStroke(1));
        
        g2.setColor(color);
        g2.fill(triangle);
        
        g2.setColor(borderColor);
        g2.draw(triangle);
    }
    
    private void drawCircleAtPosition(Graphics2D g2, int[] position, Color color, Color borderColor, double radius) {
        drawCircleAtPixel(g2, getPixelsFromPosition(position), color, borderColor, radius);
    }
    
    private void drawCircleAtPixel(Graphics2D g2, double[] pixels, Color color, Color borderColor, double radius) {
        double centerX = pixels[0];
        double centerY = pixels[1];
        
        Ellipse2D circle = new Ellipse2D.Double(centerX - radius, centerY - radius, radius * 2, radius * 2);
        
        g2.setStroke(new BasicStroke(2));
        
        g2.setColor(color);
        g2.fill(circle);
        
        g2.setColor(borderColor);
        g2.draw(circle);
    }
    
    private void drawHexagonAtPosition(int[] position, Color color, Color borderColor, Graphics g) {
        drawHexagonAtPixel(getPixelsFromPosition(position), color, borderColor, g);
    }
    
    private void drawHexagonAtPixel(double[] pixels, Color color, Color borderColor, Graphics g) {
        double centerX = pixels[0];
        double centerY = pixels[1];
        
        Path2D.Double hex = new Path2D.Double();
        for(int q = 0; q < 7; q++) {
            double radians = ((q * 60) + 30) * Math.PI / 180;
            if(q == 0) {
                hex.moveTo(centerX + mHexRadius * Math.cos(radians), centerY + mHexRadius * Math.sin(radians));
            } else {
                hex.lineTo(centerX + mHexRadius * Math.cos(radians), centerY + mHexRadius * Math.sin(radians));
            }
        }
        
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setStroke(new BasicStroke(DEFAULT_STROKE + mStrokeWidthAdjust));
        
        g2.setColor(color);
        g2.fill(hex);
        
        g2.setColor(borderColor);
        g2.draw(hex);
    }
    
    private double[] getPixelsFromPosition(int[] position) {
        int q = position[0];
        int r = position[1];
        double deltaX = ((q * mHexWidth) + ((mDx / 2) * r));
        double deltaY = (r * mDy);
        
        return new double[] { mCenterX + deltaX, mCenterY + deltaY };
    }
    
    private void drawStringCenteredBoth(Graphics2D g2, String s, int x, int y) {  
        // Find the size of string s in the font of the Graphics context "page"
        FontMetrics fm   = g2.getFontMetrics(g2.getFont());
        java.awt.geom.Rectangle2D rect = fm.getStringBounds(s, g2);
        int textHeight = (int)(rect.getHeight());
        int textWidth  = (int)(rect.getWidth());

        // Center text horizontally and vertically within provided rectangular bounds
        int textX = x - (textWidth)/2;
        int textY = y - (textHeight)/2 + fm.getAscent();
        g2.drawString(s, textX, textY);
    }
    
    private void startTranslateAnim(Tile tile, int[] from, double dx, double dy) {
        mAnimStartTime = System.currentTimeMillis();
        mAnimTransX += dx;
        mAnimTransY += dy;
        animTranslateStep(tile);
        mAnimating = true;
        
        mAnimCoordinates = from;
        
        
//        int q = from[0];
//        int r = from[1];
//        double initX = ((q * mHexWidth) + ((mDx / 2) * r));
//        double initY = (r * mDy);
//        
//        AffineTransform init = new AffineTransform();
//        init.translate(initX, initY);
//        mAnimHexagon.transform(init);
    }
    
    private void animTranslateStep(Tile tile) {
        Graphics2D g2 = (Graphics2D) getGraphics();
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setStroke(new BasicStroke(DEFAULT_STROKE + mStrokeWidthAdjust));
        g2.setColor(getTileColor(((VillageTile) tile)));
        
        float pct = (float) (System.currentTimeMillis() - mAnimStartTime) / 100f;
        double dx = mAnimTransX * Math.min(1.0, pct);
        double dy = mAnimTransY * Math.min(1.0, pct);
        
        System.out.println("animating.. " + pct + " dx: " + dx + " dy: " + dy);
        
//        mTileHexagon.translate(deltaX, deltaY);
        AffineTransform at = new AffineTransform();
        at.translate(dx, dy);
        mAnimHexagon.transform(at);
        
        g2.fill(mAnimHexagon);
        
        g2.setColor(Color.BLACK);
        g2.draw(mAnimHexagon);
      
        
        if(pct > 1.0) {
            System.out.println("ANIM END");
//            mLastOverlayCoordinates = mBoard.getOverlayCoordinates();
            mAnimating = false;
            
            mAnimTransX = 0;
            mAnimTransY = 0;
            
//            AffineTransform after = new AffineTransform();
//            after.translate(dx, dy);
//            mAnimHexagon.transform(after);
        } else {
            AffineTransform att = new AffineTransform();
            att.translate(-dx, -dy);
            mAnimHexagon.transform(att);
        }
        repaint();
    }
    
//    public void drawTile(int[] coordinates, Tile tile) {
//        tile.acceptDraw(coordinates, this);
//    }
    
    public void draw(int[] coordinates, RiceTile tile) {
        drawColoredTile(coordinates, getTileColor(tile));
    }

    public void draw(int[] coordinates, VillageTile tile) {
        drawColoredTile(coordinates, getTileColor(tile));
    }

    public void draw(int[] coordinates, IrrigationTile tile) {
        drawColoredTile(coordinates, getTileColor(tile));
    }

    public void draw(int[] coordinates, PalaceTile tile) {
        drawColoredTile(coordinates, getTileColor(tile));
    }
    
    private Color getTileColor(RiceTile t) {
        return sTileColors[TYPE_RICE];
    }
    private Color getTileColor(VillageTile t) {
        return sTileColors[TYPE_VILLAGE];
    }
//    private Color getTileColor(Developer t) {
//        return Color.CYAN;
//    }
    private Color getTileColor(PalaceTile t) {
        return sTileColors[TYPE_PALACE];
    }
    private Color getTileColor(IrrigationTile t) {
        return sTileColors[TYPE_IRRIGATION];
    }

//    public void draw(int[] coordinates, Developer tile) {
//        drawColoredDeveloper(coordinates, tile, Color.CYAN); // TODO
//    }
    
    private void drawColoredTile(int[] coordinates, Color color) {
        Graphics2D g2 = (Graphics2D) getGraphics();
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setColor(color);
        g2.setStroke(new BasicStroke(DEFAULT_STROKE + mStrokeWidthAdjust));
        
        int q = coordinates[0];
        int r = coordinates[1];
        double deltaX = ((q * mHexWidth) + ((mDx / 2) * r));
        double deltaY = (r * mDy);
        
//        mTileHexagon.translate(deltaX, deltaY);
        AffineTransform at = new AffineTransform();
        at.translate(deltaX, deltaY);
        mTileHexagon.transform(at);
        
        g2.fill(mTileHexagon);
        
        g2.setColor(Color.BLACK);
        g2.draw(mTileHexagon);
      
        AffineTransform att = new AffineTransform();
        att.translate(-deltaX, -deltaY);
        mTileHexagon.transform(att);
    }
    
    private void drawColoredDeveloper(int[] coordinates, Integer developerIndex, Color color) {
        // TODO
        Graphics2D g2 = (Graphics2D) getGraphics();
        g2.setColor(color);
        
        int q = coordinates[0];
        int r = coordinates[1];
        int deltaX = (int) ((q * mHexWidth) + ((mDx / 2) * r));
        int deltaY = (int) (r * mDy);
        
        Rectangle2D save = mDeveloperCircle.getFrame();
        mDeveloperCircle.setFrame(new Rectangle2D.Double(mCenterX + deltaX, mCenterY + deltaY, save.getWidth(), save.getHeight()));
        
        g2.draw(mTileHexagon);
        
        mDeveloperCircle.setFrame(save);
      
//        mDeveloperCircle.translate(-deltaX, -deltaY);
    }
    
    public void componentHidden(ComponentEvent arg0) {
    }

    public void componentMoved(ComponentEvent arg0) {
    }

    public void componentResized(ComponentEvent arg0) {
    	System.out.println("resized");
        initSize();
    }

    public void componentShown(ComponentEvent arg0) {
    	System.out.println("shown");
        initSize();
    }
    
    private void initSize() {
        double width = getWidth();
        double height = getHeight();
        double w = mNumColumns * 2 * Math.cos(Math.PI / 6);
        double h = (mNumRows * 3 + 1) / 2;
        double padding = width / height > w / h ? height * 0.1 : width * 0.1;
        mDrawableRect = new Rectangle2D.Double(padding, padding, width - padding, height - padding);
        
        if(Math.min(width, height) < 350) {
            mStrokeWidthAdjust = -2;
        } else if(Math.min(width, height) < 500) {
            mStrokeWidthAdjust = -1;
        } else {
            mStrokeWidthAdjust = 0;
        }
        
        // height = width / Math.cos(pi / 6)
        // width = height * Math.cos(pi / 6)
        
        // h = side * (rows * 3 + 1) / 2
        // w = width * columns = side * 2 * cos(pi / 6) * columns
        
        if(( width / height) > (w/h)) {
//            mHexHeight = height / mNumRows - 4;         // size based on height
            mHexSide = mDrawableRect.getHeight() / ((mNumRows * 3 + 1) / 2);
            mHexHeight = mHexSide * 2;
            mHexWidth = mHexSide * Math.sqrt(3);
        } else {
            mHexWidth = mDrawableRect.getWidth() / mNumColumns;
            mHexSide = mHexWidth / (2 * Math.cos(Math.PI / 6));
            mHexHeight = 2 * mHexSide;
        }
        
        mHexRadius = mHexSide / (2 * Math.sin(Math.PI / 6));
        
        mDy = (3 * mHexSide) / 2;
        mDx = mHexWidth;
        mCenterX = width / 2;
        mCenterY = height / 2 + mDy;   // TODO
        
        mTileHexagon = new Path2D.Double();
        for(int q = 0; q < 7; q++) {
            double radians = ((q * 60) + 30) * Math.PI / 180;
            if(q == 0) {
                mTileHexagon.moveTo(mCenterX + mHexRadius * Math.cos(radians), mCenterY + mHexRadius * Math.sin(radians));
            } else {
                mTileHexagon.lineTo(mCenterX + mHexRadius * Math.cos(radians), mCenterY + mHexRadius * Math.sin(radians));
            }
//            mTileHexagon.addPoint((int) (mCenterX + mHexRadius * Math.cos(radians)), 
//                    (int) (mCenterY + mHexRadius * Math.sin(radians)));
        }
        
        mAnimHexagon = new Path2D.Double();
        for(int q = 0; q < 7; q++) {
            double radians = ((q * 60) + 30) * Math.PI / 180;
            if(q == 0) {
                mAnimHexagon.moveTo(mCenterX + mHexRadius * Math.cos(radians), mCenterY + mHexRadius * Math.sin(radians));
            } else {
                mAnimHexagon.lineTo(mCenterX + mHexRadius * Math.cos(radians), mCenterY + mHexRadius * Math.sin(radians));
            }
        }
        
        double d = mHexRadius * 2 / 3;
        double rad = d / 2;
        mDeveloperCircle =  new Ellipse2D.Double(mCenterX - rad, mCenterY - rad, d, d);
        
        mBorderPath = new Path2D.Double();
        for(int[] c : mBoard.getMapCoordinates()) {
            Polygon p = new Polygon();
            for(int q = 0; q < 6; q++) {
                double radians = ((q * 60) + 30) * Math.PI / 180;
                p.addPoint((int) (mCenterX + mHexRadius * Math.cos(radians)), 
                        (int) (mCenterY + mHexRadius * Math.sin(radians)));
            }
            
            int q = c[0];
            int r = c[1];
            int deltaX = (int) ((q * mHexWidth) + ((mDx / 2) * r));
            int deltaY = (int) (r * mDy);
            
            p.translate(deltaX, deltaY);
            mBorderPath.append(p.getPathIterator(null), false);
        }
        AffineTransform tran = new AffineTransform();
        mBorderPath.transform(tran);
        mBorderShape = new Polygon();
        
        System.out.println("actual ratio: " + ((double) mBorderPath.getBounds().width / (double)mBorderPath.getBounds().height));
//        for(int q = 0; q < 6; q++) {
//            double radians = ((q * 60) + 30) * Math.PI / 180;
//            mBorderShape.addPoint((int) (mCenterX + mHexRadius * Math.cos(radians)), 
//                    (int) (mCenterY + mHexRadius * Math.sin(radians)));
//        }
//        mBorderPath.append(mBorderShape.getPathIterator(null), true);
        
        repaint();
    }

    @Override
    public void onModelChange(ObservableModel model) {
        repaint();
    }
}
